package main

import (
	"encoding/xml"
	"fmt"
	"net"
	"strings"
	"time"
)

const (
	xmlHead = `<?xml version="1.0" encoding="utf-8"?>`
)

var (
	tmpVideoParams PushVideoParaType
	tmpAudioParams PushAudioParaType
)

func LOGIN_MEDIA_SERVER_CMD_handle(recvXmlData *[]byte, conn *net.Conn) {
	fmt.Println("login:recvXmlData:", string(*recvXmlData))
	recvObj := LoginoutDataType{}
	err := xml.Unmarshal(*recvXmlData, &recvObj)
	if err != nil {
		fmt.Println("login:Unmarshal package fail !", string(*recvXmlData))
		return
	}

	//fmt.Println("login:recvObj:", recvObj)

	mac := getMacFromBytesSlice([]byte(recvObj.IdentityId))
	state := addTcpConnToMapAccordingToMac(&mac, (*conn).RemoteAddr().String())

	sendObj := CommonResponseDataType{}
	sendObj.SessionId = recvObj.SessionId
	sendObj.State = state
	sendXmlRealData, err := xml.Marshal(sendObj)
	if err != nil {
		fmt.Println("login:create send back xml package fail !", sendObj)
		return
	}

	//fmt.Println("login:sendObj:", sendObj)
	//fmt.Println("login:sendXmlRealData:", string(sendXmlRealData))

	createPackageSend(&sendXmlRealData, LOGIN_MEDIA_SERVER_CMD_REP, conn)
}

func LOGOUT_MEDIA_SERVER_CMD_handle(recvXmlData *[]byte, conn *net.Conn) {
	recvObj := LoginoutDataType{}
	err := xml.Unmarshal(*recvXmlData, &recvObj)
	if err != nil {
		fmt.Println("logout:Unmarshal package fail !", *recvXmlData)
		return
	}

	mac := getMacFromBytesSlice([]byte(recvObj.IdentityId))
	state := deleteTcpConnToMapAccordingToMac(&mac, ((*conn).RemoteAddr().String()))

	//fmt.Println("logout:state:", state)
	fmt.Println("logout:state:", state, "recvXmlData:", string(*recvXmlData))
	//fmt.Println("logout:recvObj:", recvObj)
}

func REQUEST_PUSH_STREAM_TO_MEDIA_SERVER_CMD_handle(recvXmlData *[]byte, conn *net.Conn) {
	recvObj := RequestPushStreamDataType{}
	err := xml.Unmarshal(*recvXmlData, &recvObj)
	if err != nil {
		fmt.Println("push:Unmarshal package fail !", string(*recvXmlData))
		return
	}

	mac := getMacFromBytesSlice([]byte(recvObj.IdentityId))
	streamId := stoi(recvObj.MediaId)
	v := (recvObj.MediaVideo != 0)
	a := (recvObj.MediaAudio != 0)

	state := udpClientPushStream(&mac, streamId, v, a, (*conn).RemoteAddr().String(),
		&(recvObj.VideoParam), &(recvObj.AudioParm))

	sendObj := CommonResponseDataType{}
	sendObj.SessionId = recvObj.SessionId
	sendObj.State = state
	sendXmlRealData, err := xml.Marshal(sendObj)
	if err != nil {
		fmt.Println("push:create send back xml package fail !", sendObj)
		return
	}

	fmt.Println("push:recvXmlData:", string(*recvXmlData))
	//fmt.Println("push:recvObj:", recvObj)

	createPackageSend(&sendXmlRealData, REQUEST_PUSH_STREAM_TO_MEDIA_SERVER_CMD_REP, conn)
}

func CANCEL_PUSH_STREAM_TO_MEDIA_SERVER_CMD_handle(recvXmlData *[]byte, conn *net.Conn) {
	recvObj := CanclePushStreamDataType{}
	err := xml.Unmarshal(*recvXmlData, &recvObj)
	if err != nil {
		fmt.Println("login:Unmarshal package fail !", *recvXmlData)
		return
	}

	mac := getMacFromBytesSlice([]byte(recvObj.IdentityId))
	streamId := stoi(recvObj.MediaId)
	v := (recvObj.MediaVideo != 0)
	a := (recvObj.MediaAudio != 0)
	state := udpClientCanclePushStream(&mac, streamId, v, a, (*conn).RemoteAddr().String())

	sendObj := CommonResponseDataType{}
	sendObj.SessionId = recvObj.SessionId
	sendObj.State = state
	sendXmlRealData, err := xml.Marshal(sendObj)
	if err != nil {
		fmt.Println("cancle push:create send back xml package fail !", sendObj)
		return
	}

	fmt.Println("canclePush:recvXmlData:", string(*recvXmlData))
	//fmt.Println("canclePush:recvObj:", recvObj)

	createPackageSend(&sendXmlRealData, CANCEL_PUSH_STREAM_TO_MEDIA_SERVER_CMD_REP, conn)
}

func REQUEST_STREAM_FROM_MEDIA_SERVER_CMD_handle(recvXmlData *[]byte, conn *net.Conn) {
	recvObj := RequestPullStreamDataType{}
	err := xml.Unmarshal(*recvXmlData, &recvObj)
	if err != nil {
		fmt.Println("pull:Unmarshal package fail !", string(*recvXmlData))
		return
	}

	mac := getMacFromBytesSlice([]byte(recvObj.IdentityId))
	streamId := stoi(recvObj.MediaId)
	v := (recvObj.Video != 0)
	a := (recvObj.Audio != 0)
	state, video, audio, videoPara, audioPara := udpClientPullStream(&mac, streamId, v, a, (*conn).RemoteAddr().String())

	sendObj := ResponsePullStreamDataType{}
	sendObj.SessionId = recvObj.SessionId
	sendObj.State = state

	sendObj.MediaVideo = video
	sendObj.MediaAudio = audio
	sendObj.VideoParam = videoPara
	sendObj.AudioParam = audioPara

	sendXmlRealData, err := xml.Marshal(sendObj)
	if err != nil {
		fmt.Println("pull:create send back xml package fail !", sendObj)
		return
	}

	fmt.Println("pull:recvXmlData:", string(*recvXmlData))
	//fmt.Println("pull:recvObj:", recvObj)

	createPackageSend(&sendXmlRealData, REQUEST_STREAM_FROM_MEDIA_SERVER_CMD_REP, conn)
}

func CANCEL_STREAM_TO_MEDIA_SERVER_CMD_handle(recvXmlData *[]byte, conn *net.Conn) {
	recvObj := CanclePullStreamDataType{}
	err := xml.Unmarshal(*recvXmlData, &recvObj)
	if err != nil {
		fmt.Println("cancle pull:Unmarshal package fail !", string(*recvXmlData))
		return
	}

	mac := getMacFromBytesSlice([]byte(recvObj.IdentityId))
	streamId := stoi(recvObj.MediaId)
	v := (recvObj.Video != 0)
	a := (recvObj.Audio != 0)
	state := udpClientCanclePullStream(&mac, streamId, v, a, (*conn).RemoteAddr().String())

	sendObj := CommonResponseDataType{}
	sendObj.SessionId = recvObj.SessionId
	sendObj.State = state
	sendXmlRealData, err := xml.Marshal(sendObj)
	if err != nil {
		fmt.Println("cancle pull:create send back xml package fail !", sendObj)
		return
	}

	fmt.Println("cancle pull:recvXmlData:", string(*recvXmlData))
	//fmt.Println("cancle pull:recvObj:", recvObj)

	createPackageSend(&sendXmlRealData, CANCEL_STREAM_TO_MEDIA_SERVER_CMD_REP, conn)
}

func SERVER_CLIENT_KEEPALIVE_CMD_handle(recvXmlData *[]byte, conn *net.Conn) {
	ret := refreshSaveHeartbeatTime((*conn).RemoteAddr().String())
	if ret < 0 {
		fmt.Println("SERVER_CLIENT_KEEPALIVE_CMD_handle: can not find this tcp connect !", (*conn).RemoteAddr().String())
		return
	}
}

func refreshSaveHeartbeatTime(tcpAddrString string) int {
	nowTime := time.Now().Unix()
	ret := -1

	tcpClientListRwLock.RLock()
	for i := range tcpClientList {
		e := &tcpClientList[i]
		if strings.Compare(tcpAddrString, e.conn.RemoteAddr().String()) == 0 {
			e.lastHeartbeatTime = nowTime
			ret = 0
			break
		}
	}
	tcpClientListRwLock.RUnlock()

	return ret
}
